如果有自己串過一次 LLM API,應該會發現做出第一個 AI Demo 真的沒有想像中困難,準備一段 Prompt、把使用者輸入丟進去,再把模型回傳的內容顯示出來,一個最基本的 AI 功能其實很快就能跑。
我以前做到這一步的時候,也很容易有一種「差不多完成了」的感覺,因為畫面有回答、問題大部分看起來也答得不錯,Demo 給別人看的時候通常還滿順,但真的開始把 AI 放進系統之後,才會慢慢發現最麻煩的地方,幾乎都是 Demo 當下看不到的東西。
自己測系統的時候,我其實很清楚它是怎麼設計的,所以自然會輸入一些「正常問題」,例如做文件問答,我會問文件裡真的有答案的內容;要求模型輸出 JSON,我也會很完整地告訴它需要哪些欄位。
資料乾淨、API 正常、Prompt 也是自己寫的,這種狀況下模型當然很容易表現得不錯,但真的有人開始使用之後,輸入就不一定會長這樣。
幫我整理一下昨天那個東西。
這段看不懂,反正你幫我處理。
甚至只是多講一句:
可以順便解釋一下嗎?
原本要求模型只回 JSON,結果它很熱心地變成:
好的,以下是整理後的結果:
{
...
}
人看起來完全沒問題,程式的 parser 卻可能直接失敗,這時候才會發現 AI 系統的問題不是只有「模型會不會回答」,還包括回答能不能被下一個程式接住、失敗的時候知不知道發生在哪裡,以及同一個輸入明天再跑一次,會不會突然變成另一種格式。
一般程式很好判斷成功或失敗:
result = add(1, 2)
assert result == 3
但 LLM 沒這麼單純。
假設我要它整理一封 Email,可以回傳摘要、分類、優先級,看起來三個欄位都有,可是分類錯了;也可能內容完全正確,但 JSON 格式多了一行說明;甚至格式跟內容都沒問題,只是這次用了比原本多很多的 Token。
這些都算是「模型有回答」,卻不代表這個 Request 真的成功,所以如果要把 AI 當成系統的一部分,我至少得開始記:
輸出格式有沒有通過
內容有沒有答對
用了多少 Token
花了多少時間
失敗屬於哪一種
以前我可能只會打開畫面問幾題,覺得答案看起來 OK 就繼續做功能,現在反而覺得應該先把什麼叫「OK」講清楚,不然之後 Prompt、模型或資料一改,根本不知道系統到底是變好還是變差。
另一個我自己很常做的事,就是模型輸出不符合預期時先改 Prompt,格式亂掉,就在 Prompt 裡補:
請務必只輸出 JSON
不要加入其他文字
一定要包含以下欄位
還是不穩,再補一句,最後 Prompt 越來越長,好像每遇到一個問題就再加一條規則。
但後來重新看這些問題時會發現,有些東西本來就不應該全部交給 Prompt,例如一個欄位是不是必填、資料型別是不是正確、狀態能不能只出現固定幾種值,這些其實更像程式規則。
Prompt
→ 告訴模型要做什麼
Schema
→ 限制資料應該長什麼樣
Validation
→ 檢查結果到底能不能用
如果把這三件事全部塞進 Prompt,就算今天剛好成功,也很難保證之後換模型、換輸入還是一樣。
所以我不想再把 LLM 當成一個輸入文字就會吐出答案的黑盒子,而是把它當成整個軟體系統裡其中一個會出錯、需要驗證的 Component。
今天沒有急著加 RAG、Agent 或其他比較吸睛的功能,我先把目前最簡單的流程畫出來:
User
↓
Input
↓
LLM
↓
Output
接下來再慢慢往中間補:
Validation
Structured Output
Evaluation
Retrieval
Tools
Tracing
Cost
Latency
最後希望得到的,不是一個「大部分時候回答得不錯」的 Demo,而是一個至少可以知道自己哪裡壞掉、改版後能重新測,而且真的敢接到其他程式後面的 AI System。
第一個要處理的就是最常遇到的格式問題,明天先從 Structured Output 開始,看能不能讓模型別再每次都自由發揮。